Repository navigation
fix(interpreter): budget pending array expansions - #2670
Merged
Merged
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
bashkit | 14cfe29 | Commit Preview URL Branch Preview URL |
Oct 10 2026, 11:34 PM |
chaliy
force-pushed
the
codex/array-preexpansion-memory
branch
from
October 10, 2026 23:14
85cbd79 to
3f8a4d1
Compare
expand_word_inner awaited expand_word_buffer inline, embedding the loop state machine in every $(...) nesting level. Depth-32 aborted under coverage instrumentation (same class as #1089). Box::pin moves the buffer state to the heap, restoring the upstream stack threshold.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Indexed/assoc array literals with duplicate subscripts now charge every pending element value against the live-intermediate byte budget, not just the values that survive. The expansion pass also holds the budget as leases instead of materializing duplicate copies, so transient memory stays bounded by the configured limit.
Why
Finding [SECURITY-ARRAY-PREEXPANSION-MEMORY]: a literal such as
a=([0]= \$big [0]= \$big ...)(2000 dups x 1MB = ~2GB pending) bypassed the byte cap because the committer charged only the final surviving value. The in-memory peak scaled with the number of duplicate entries, an unauthenticated memory-exhaustion vector for any service executing scripts under a memory limit.Before / After
Before (vulnerable code, budget check on final values only): 2GB transient allocation succeeds under a 10MB budget.
After (fixed): the same shape fails fast with a memory-limit error and the shell stays usable:
indexed_array_pending_values_share_live_byte_limit: dup-subscript literal exhausts the live-byte limit -> error, shell usable afterwardassoc_array_pending_values_share_live_byte_limit: assoc dup-key literal with distinct live entries -> error, shell usable afterwardassoc_array_duplicate_keys_share_live_byte_limit: dup assoc keys charged per occurrencelimits.rs/interpreter/tests.rscover small-literal fast path, dup-subscript commit charging, lease reuse, exhaustion errors, live-usage accountingE2E smoke (hardened profile, 8KB value x 1200 dup subscripts = ~9.6MB pending vs 8MB limit): shell prints the memory-limit error and exits 1 instead of ballooning.
Risk
just testslice run in CI.Checklist
Produced by yolop